package com.zmykj.hik.hikService.Service.Alarm;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;


import com.alibaba.fastjson.JSONObject;
import com.sun.jna.Native;

import com.zmykj.hik.hikService.Common.CommonClass;
import com.zmykj.hik.hikService.Common.HikStringUtils;
import com.zmykj.hik.hikService.Service.Alarm.ISUPAMSByJNA.EHomeMsgCallBack;
import com.zmykj.hik.hikService.Service.Alarm.ISUPAMSByJNA.NET_EHOME_ALARM_ISAPI_INFO;
import com.zmykj.hik.hikService.Service.Alarm.ISUPAMSByJNA.NET_EHOME_ALARM_LISTEN_PARAM;
import com.zmykj.hik.hikService.Service.Alarm.ISUPAMSByJNA.NET_EHOME_ALARM_MSG;
import com.zmykj.hik.hikService.Service.Alarm.ISUPAMSByJNA.NET_EHOME_FACESNAP_REPORT;
import com.zmykj.hik.hikService.Service.Alarm.ISUPAMSByJNA.NET_EHOME_HEATMAP_REPORT;
import com.zmykj.hik.hikService.Service.Alarm.ISUPAMSByJNA.NET_EHOME_NOTICE_PICURL;
import com.zmykj.hik.hikService.Service.Alarm.ISUPAMSByJNA.NET_EHOME_XML_DATA;
import com.zmykj.hik.hikService.Common.CommonClass.StringPointer;
import com.zmykj.hik.hikService.Common.CommonMethod;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.zmykj.hik.rocketMQ.RocketConfig;
import com.zmykj.hik.rocketMQ.RocketMqProducer;
import javafx.beans.binding.ObjectExpression;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EAlarm {
	private final static Logger logger = LoggerFactory.getLogger("hik-equipment");
	private static ISUPAMSByJNA m_AMSInstance = null;
	private boolean m_bIsRunning = false;
	private static EHomeMsgCallBack m_fEHomeMsgCallBack = null; 
	public  NativeLong m_lAlarmListenHandle;

	//Alarm module initialization and monitoring
	public EAlarm() {
        if(m_AMSInstance == null)
        {
            if(!CreateAMSInstance())
            {
                System.out.println("Load AMS fail");
                return;
            }
        }

		m_lAlarmListenHandle = new NativeLong(-1);
		
		if(m_AMSInstance.NET_EALARM_Init())
		{
            CommonMethod.logRecord("INFO", "[NET_EALARM_Init]->EHomeAMS initialize successfully");

            //Open alarm module log
            m_AMSInstance.NET_EALARM_SetLogToFile(3, "./EHomeSdkLog", true);

            String sLibComPath = "";
            if(CommonMethod.isLinux())
            {
                sLibComPath = CommonMethod.GetLibPathByArch() + "HCAapSDKCom/";
                StringPointer strPointer = new StringPointer(sLibComPath);
                strPointer.write();
                if(m_AMSInstance.NET_EALARM_SetSDKLocalCfg(5, strPointer.getPointer()))
                    System.out.println("[Alarm]ComPath Load Successfully:" + sLibComPath);
                else
                    System.out.println("[Alarm]ComPath Load Failed!:" + sLibComPath +
                            ", errorCode: " + m_AMSInstance.NET_EALARM_GetLastError());
                strPointer.read();
            }

			CommonClass.NET_EHOME_LOCAL_GENERAL_CFG m_struLocalCfg = new CommonClass.NET_EHOME_LOCAL_GENERAL_CFG();
			m_struLocalCfg.byAlarmPictureSeparate = 1;
			m_struLocalCfg.write();
			m_AMSInstance.NET_EALARM_SetSDKLocalCfg(4,m_struLocalCfg.getPointer());

            NET_EHOME_ALARM_LISTEN_PARAM struAlarmListenParam = new NET_EHOME_ALARM_LISTEN_PARAM();
            struAlarmListenParam.byProtocolType = (byte)CommonMethod.GetServerInfo().dwAlarmServerType;
			CommonMethod.ByteCopy(CommonMethod.GetListenInfo().struAMSListenParam.struAddress.szIP, struAlarmListenParam.struAddress.szIP);
			struAlarmListenParam.struAddress.wPort = CommonMethod.GetListenInfo().struAMSListenParam.struAddress.wPort;

            StartListen(struAlarmListenParam);
		}else{
            CommonMethod.logRecord("ERROR", "[NET_ESS_Init]->ESS initialize Failed, errorCode:" +
                    m_AMSInstance.NET_EALARM_GetLastError());
        }
	}

	public boolean StartListen(NET_EHOME_ALARM_LISTEN_PARAM struAlarmListenParam) {
		if (m_fEHomeMsgCallBack == null) {
			m_fEHomeMsgCallBack = new FEHomeMsgCallBack();
			struAlarmListenParam.fnMsgCb = m_fEHomeMsgCallBack;
		}
		struAlarmListenParam.byUseCmsPort = CommonMethod.GetListenInfo().struAMSListenParam.byUseCmsPort;
		struAlarmListenParam.pUserData = null;
		m_lAlarmListenHandle = m_AMSInstance.NET_EALARM_StartListen(struAlarmListenParam);
		if (m_lAlarmListenHandle.longValue() < 0) {
			CommonMethod.logRecord("ERROR", "[NET_EALARM_StartListen]->AMS start listen failed,errorCode is " +
                    m_AMSInstance.NET_EALARM_GetLastError());
			return false;
		} else {
            m_bIsRunning = true;
			CommonMethod.logRecord("INFO", "[NET_EALARM_StartListen]->AMS start listen successfully->" + 
					"listenProctol: " + (int)struAlarmListenParam.byProtocolType + "\t" +
					"listenAddress: " + CommonMethod.byteToString(struAlarmListenParam.struAddress.szIP) + "\t" +
					"listenPort: "    + struAlarmListenParam.struAddress.wPort);
			return true;
		}
	}

	public boolean StopListen() {

		boolean bIsStopAlarmListen = m_AMSInstance.NET_EALARM_StopListen(m_lAlarmListenHandle.longValue());
		if (bIsStopAlarmListen) {
		    m_bIsRunning = false;
			CommonMethod.logRecord("INFO", "[NET_EALARM_StopListen]->AMS stop listen successfully");
			m_lAlarmListenHandle.setValue(-1);
		} else {
			CommonMethod.logRecord("ERROR", "[NET_EALARM_StopListen]->AMS stop listen failed, errorCode is" +
					m_AMSInstance.NET_EALARM_GetLastError());
		}

		return bIsStopAlarmListen;
	}

	public void StopElarm() {
		StopListen();

		m_AMSInstance.NET_EALARM_Fini();

		CommonMethod.logRecord("INFO", "[NET_EALARM_Fini]->EHomeAMS release resource successfully");
	}

	//Alarm message callback
	private class FEHomeMsgCallBack implements EHomeMsgCallBack {
		public boolean invoke(NativeLong iHandle, NET_EHOME_ALARM_MSG pAlarmMsg, Pointer pUser) {

			System.out.println("EHomeMsgCallBack: " + pAlarmMsg.dwAlarmType + "dwAlarmInfoLen:" +
								pAlarmMsg.dwAlarmInfoLen + "dwXmlBufLen:" + pAlarmMsg.dwXmlBufLen);

			StringBuffer strOutBuff = new StringBuffer();
			JSONObject objAlarmInfo = new JSONObject();

			//Only the ISAPI alarm will have httpUrl
			if (pAlarmMsg.pHttpUrl != null) {
				pAlarmMsg.dwAlarmType = ISUPAMSByJNA.EHOME_ISAPI_ALARM;
			}

			try {
				switch (pAlarmMsg.dwAlarmType) {
					case ISUPAMSByJNA.EHOME_ALARM_UNKNOWN ://未知报警
					{
						objAlarmInfo.put("AlarmType", "UNKNOWN");
						break;
					}
					case ISUPAMSByJNA.EHOME_ALARM ://基本报警
					{
						objAlarmInfo.put("AlarmType", "DEVICE_STATUS_REPORT");
						ProcessEhomeXMLAlarm(pAlarmMsg.pXmlBuf, pAlarmMsg.dwXmlBufLen, strOutBuff);
						break;
					}
					case ISUPAMSByJNA.EHOME_ALARM_HEATMAP_REPORT ://热度图报警
					{
						objAlarmInfo.put("AlarmType", "HEATMAP_REPORT");
						ProcessEhomeHeatMapReport(pAlarmMsg.pAlarmInfo, pAlarmMsg.dwAlarmInfoLen, strOutBuff);
						break;
					}
					case ISUPAMSByJNA.EHOME_ALARM_FACESNAP_REPORT ://人脸抓拍报警
					{
						objAlarmInfo.put("AlarmType", "FACESNAP_REPORT");
						ProcessEhomeFaceSnapReport(pAlarmMsg.pAlarmInfo, pAlarmMsg.dwAlarmInfoLen, strOutBuff);
						break;
					}
					case ISUPAMSByJNA.EHOME_ALARM_GPS ://GPS 报警
					{
						objAlarmInfo.put("AlarmType", "GPS");
						ProcessEhomeXMLAlarm(pAlarmMsg.pXmlBuf, pAlarmMsg.dwXmlBufLen, strOutBuff);
						break;
					}
					case ISUPAMSByJNA.EHOME_ALARM_CID_REPORT ://报警主机的 CID 报警
					{
						objAlarmInfo.put("AlarmType", "CID_REPORT");
						ProcessEhomeCid(pAlarmMsg.pAlarmInfo, pAlarmMsg.dwAlarmInfoLen, pAlarmMsg.pXmlBuf, pAlarmMsg.dwXmlBufLen, strOutBuff);
						break;
					}
					case ISUPAMSByJNA.EHOME_ALARM_NOTICE_PICURL : //图片 URL 报警
					{
						objAlarmInfo.put("AlarmType", "PictureURL_REPORT");
						ProcessEhomeNoticePicUrl(pAlarmMsg.pAlarmInfo, pAlarmMsg.dwAlarmInfoLen, pAlarmMsg.pXmlBuf, pAlarmMsg.dwXmlBufLen, strOutBuff);
						break;
					}
					case ISUPAMSByJNA.EHOME_ALARM_NOTIFY_FAIL : //异步失败通知报警
					{
						objAlarmInfo.put("AlarmType", "AsyncFail_REPORT");
						ProcessEhomeNotifyFail(pAlarmMsg.pAlarmInfo, pAlarmMsg.dwAlarmInfoLen, pAlarmMsg.pXmlBuf, pAlarmMsg.dwXmlBufLen, strOutBuff);
						break;
					}
					case ISUPAMSByJNA.EHOME_ALARM_ACS : //门禁事件报警
					{
						objAlarmInfo.put("AlarmType", "ACS_Event_REPORT");
						ProcessEhomeXMLAlarm(pAlarmMsg.pXmlBuf, pAlarmMsg.dwXmlBufLen, strOutBuff);
						Map alaemAcs = HikStringUtils.XmlToMap(strOutBuff.toString());
						String MinorType = ((Map)alaemAcs.get("Params")).get("MinorType").toString();
						if(ISUPAMSByJNA.EHOME_MINOR_FINGERPRINT_COMPARE_PASS.equals(MinorType) || ISUPAMSByJNA.EHOME_MINOR_MINOR_FACE_VERIFY_PASS.equals(MinorType)){
							Map map = new HashMap();
							map.put("userId",((Map)alaemAcs.get("Params")).get("employeeNoString").toString());
							map.put("date",((Map)alaemAcs.get("Params")).get("Time").toString());
							map.put("deviceID",((Map)alaemAcs.get("Params")).get("DeviceID").toString());
							map.put("rocketMqKey", UUID.randomUUID().toString());
							try {
								map.put("PicDataUrl",((Map)alaemAcs.get("Params")).get("PicDataUrl").toString());
							} catch (Exception e) {
								//e.printStackTrace();
							}
							RocketMqProducer.sendMsgIntime(RocketConfig.HIK_MESSAGE,RocketConfig.HIK_MESSAGE_SIGNIN, map.get("rocketMqKey").toString(),JSONObject.toJSONString(map));
							logger.info("RocketMq："+JSONObject.toJSONString(map));
						}

						break;
					}
					case ISUPAMSByJNA.EHOME_ALARM_WIRELESS_INFO : //无线网络报警
					{
						objAlarmInfo.put("AlarmType", "WIRELESS_INFO_REPORT");
						ProcessEhomeWirelessInfo(pAlarmMsg.pAlarmInfo, pAlarmMsg.dwAlarmInfoLen, pAlarmMsg.pXmlBuf, pAlarmMsg.dwXmlBufLen, strOutBuff);
						break;
					}
					case ISUPAMSByJNA.EHOME_ISAPI_ALARM : //通过 HTTP 上传的报警
					{
						objAlarmInfo.put("AlarmType", "ISAPI_REPORT");
						ProcessHttpAlarmInfo(pAlarmMsg.pAlarmInfo, pAlarmMsg.dwAlarmInfoLen, pAlarmMsg.pHttpUrl, pAlarmMsg.dwHttpUrlLen, strOutBuff);
						break;
					}
					case ISUPAMSByJNA.EHOME_ALARM_MPDCDATA : //车载客流统计报警
					{
						objAlarmInfo.put("AlarmType", "MPDC_DATA_REPORT");
						ProcessEhomeMPDCData(pAlarmMsg.pAlarmInfo, pAlarmMsg.dwAlarmInfoLen, pAlarmMsg.pHttpUrl, pAlarmMsg.dwHttpUrlLen, strOutBuff);
						break;
					}
					default :
						break;
				}

                //Package the alarm content and send it to the front end via Websocket
				SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
				String sDateTimeNow = df.format(new Date());
				String sDevSerial = CommonMethod.byteToString(pAlarmMsg.sSerialNumber);
				objAlarmInfo.put("DevNumber", sDevSerial);
				objAlarmInfo.put("DateTime", sDateTimeNow);
				objAlarmInfo.put("AlarmContent", strOutBuff.toString());
				System.out.println(strOutBuff.toString());
				/*System.out.println(objAlarmInfo.toString());*/
				//logger.debug(strOutBuff.toString());
				logger.info(objAlarmInfo.toString());
				//CommonMethod.sendString(WebSocketService.MessageType.AlarmInfo.value(), objAlarmInfo.toString());
			} catch (Exception ex) {
                ex.printStackTrace();
			}
			return true;
		}
	}

	private static void ProcessEhomeXMLAlarm(Pointer pXml, int dwXmlLen, StringBuffer strOutBuffer) {
		try{
		    //1. Get the class name of the alarm content
			String sClassName = NET_EHOME_XML_DATA.class.getName();
			//2. Pull the alarm message in Pointer into this class through reflection
			NET_EHOME_XML_DATA struXMLData = (NET_EHOME_XML_DATA) CommonMethod.WritePointerDataToClass(pXml, sClassName);
			
			String strXML = new String(struXMLData.byXMLData, 0, dwXmlLen);
			strOutBuffer.append(strXML);
		}catch(Exception ex){
			ex.printStackTrace();
		}
	}

	private static void ProcessEhomeHeatMapReport(Pointer pStru, int dwStruLen, StringBuffer strOutBuffer) {
		try{
		    //Same as above（Comment）
			String sClassName = NET_EHOME_HEATMAP_REPORT.class.getName();
			NET_EHOME_HEATMAP_REPORT struHeatMapData = (NET_EHOME_HEATMAP_REPORT) CommonMethod.WritePointerDataToClass(pStru, sClassName);
			
			String strData = "[HEATMAPREPORT]\nDeviceID: "+ CommonMethod.byteToString(struHeatMapData.byDeviceID) +
					"\nChannel: "+ struHeatMapData.dwVideoChannel +"\nStartTime: "+ CommonMethod.byteToString(struHeatMapData.byStartTime) +
					"\nStopTime: "+ CommonMethod.byteToString(struHeatMapData.byStopTime) +"\nHeatMapValue: "+ struHeatMapData.struHeatmapValue.dwMaxHeatMapValue +
					"  "+ struHeatMapData.struHeatmapValue.dwMinHeatMapValue +"  "+ struHeatMapData.struHeatmapValue.dwTimeHeatMapValue +
					"\nSize: "+ struHeatMapData.struPixelArraySize.dwLineValue +"  "+ struHeatMapData.struPixelArraySize.dwColumnValue +"\n";
			strOutBuffer.append(strData);
		}catch(Exception ex){
			ex.printStackTrace();
		}	
	}

	private static void ProcessEhomeFaceSnapReport(Pointer pStru, int dwStruLen, StringBuffer strOutBuffer) {
		JSONObject jsonFaceSnapReport = new JSONObject();
		try {
			String sClassName = NET_EHOME_FACESNAP_REPORT.class.getName();
			NET_EHOME_FACESNAP_REPORT struFaceSnapReport = (NET_EHOME_FACESNAP_REPORT) CommonMethod.WritePointerDataToClass(pStru, sClassName);
			
			JSONObject jsonInParam = new JSONObject();
			jsonInParam.put("DeviceID", CommonMethod.byteToString(struFaceSnapReport.byDeviceID));
			jsonInParam.put("Channel", struFaceSnapReport.dwVideoChannel);
			jsonInParam.put("Time",    CommonMethod.byteToString(struFaceSnapReport.byAlarmTime));
			jsonInParam.put("PicID",   struFaceSnapReport.dwFacePicID);
			jsonInParam.put("Score",   struFaceSnapReport.dwFaceScore);
			jsonInParam.put("TargetID", struFaceSnapReport.dwTargetID);
			
			JSONObject jsonTargetZone = new JSONObject();
			jsonTargetZone.put("x",      struFaceSnapReport.struTarketZone.dwX);
			jsonTargetZone.put("y",      struFaceSnapReport.struTarketZone.dwY);
			jsonTargetZone.put("width",  struFaceSnapReport.struTarketZone.dwWidth);
			jsonTargetZone.put("height", struFaceSnapReport.struTarketZone.dwHeight);
			jsonInParam.put("TargetZone", jsonTargetZone);
			
			JSONObject jsonFacePictureZone = new JSONObject();
			jsonFacePictureZone.put("x",      struFaceSnapReport.struFacePicZone.dwX);
			jsonFacePictureZone.put("y",      struFaceSnapReport.struFacePicZone.dwY);
			jsonFacePictureZone.put("width",  struFaceSnapReport.struFacePicZone.dwWidth);
			jsonFacePictureZone.put("height", struFaceSnapReport.struFacePicZone.dwHeight);
			jsonInParam.put("FacePictureZone", jsonFacePictureZone);
			
			JSONObject jsonHumanFeature = new JSONObject();
			jsonHumanFeature.put("AgeGroup",      struFaceSnapReport.struHumanFeature.byAgeGroup);
			jsonHumanFeature.put("Sex",      struFaceSnapReport.struHumanFeature.bySex);
			jsonHumanFeature.put("IsEyeGlass",  struFaceSnapReport.struHumanFeature.byEyeGlass);
			jsonHumanFeature.put("IsMask", struFaceSnapReport.struHumanFeature.byMask);
			jsonInParam.put("HumanFeature", jsonHumanFeature);
			
			jsonInParam.put("Duration", struFaceSnapReport.dwStayDuration);
			jsonInParam.put("FacePicLen", struFaceSnapReport.dwFacePicLen);
			jsonInParam.put("FacePicUrl", CommonMethod.byteToString(struFaceSnapReport.byFacePicUrl));
			jsonInParam.put("BackGroundPicLen", struFaceSnapReport.dwBackgroudPicLen);
			jsonInParam.put("BackGroundPicUrl", CommonMethod.byteToString(struFaceSnapReport.byBackgroudPicUrl));
			
			jsonFaceSnapReport.put("FaceSnapReport", jsonInParam);
		} catch (Exception e) {
			e.printStackTrace();
		}
		strOutBuffer.append(jsonFaceSnapReport.toString());
	}

	private static void ProcessEhomeCid(Pointer pStru, int dwStruLen, Pointer pXml, int dwXmlLen, StringBuffer strOutBuffer) {

	}

	private static void ProcessEhomeNoticePicUrl(Pointer pStru, int dwStruLen, Pointer pXml, int dwXmlLen, StringBuffer strOutBuffer) {
		JSONObject jsonNoticePicReport = new JSONObject();
		try{
			String sClassName = NET_EHOME_NOTICE_PICURL.class.getName();
			NET_EHOME_NOTICE_PICURL struNoticePicReport = (NET_EHOME_NOTICE_PICURL) CommonMethod.WritePointerDataToClass(pStru, sClassName);
			
			JSONObject jsonInParam = new JSONObject();
			jsonInParam.put("DeviceID", CommonMethod.byteToString(struNoticePicReport.byDeviceID));
			jsonInParam.put("PictureType", struNoticePicReport.wPicType);
			jsonInParam.put("Time",    CommonMethod.byteToString(struNoticePicReport.byAlarmTime));
			jsonInParam.put("AlarmType",   struNoticePicReport.wAlarmType);
			jsonInParam.put("AlarmChan",   struNoticePicReport.dwAlarmChan);
			jsonInParam.put("CaptureChan", struNoticePicReport.dwCaptureChan);
			jsonInParam.put("PicTime",    CommonMethod.byteToString(struNoticePicReport.byPicTime));
			jsonInParam.put("PicUrl",    CommonMethod.byteToString(struNoticePicReport.byPicUrl));
			jsonInParam.put("ManualSnapSeq", struNoticePicReport.dwManualSnapSeq);
			jsonNoticePicReport.put("NoticePicReport", jsonInParam);
		}catch(Exception ex){
			ex.printStackTrace();
		}
		strOutBuffer.append(jsonNoticePicReport.toString());
	}

	private static void ProcessEhomeNotifyFail(Pointer pStru, int dwStruLen, Pointer pXml, int dwXmlLen, StringBuffer strOutBuffer) {

	}

	private static void ProcessEhomeWirelessInfo(Pointer pStru, int dwStruLen, Pointer pXml, int dwXmlLen, StringBuffer strOutBuffer) {

	}

	private static void ProcessEhomeMPDCData(Pointer pStru, int dwStruLen, Pointer pUrl, int dwUrlLen, StringBuffer strOutBuffer) {

	}

	private static void ProcessHttpAlarmInfo(Pointer pStru, int dwStruLen, Pointer pUrl, int dwUrlLen, StringBuffer strOutBuffer) {
		if(pStru == null)
			return;
		
		try{
			String sClassName = NET_EHOME_ALARM_ISAPI_INFO.class.getName();
			NET_EHOME_ALARM_ISAPI_INFO struISAPIStru = (NET_EHOME_ALARM_ISAPI_INFO) CommonMethod.WritePointerDataToClass(pStru, sClassName);
			strOutBuffer.append(struISAPIStru.pAlarmData);
			
		}catch(Exception ex){
			ex.printStackTrace();
		}
	}

    private boolean CreateAMSInstance()
    {
        if(m_AMSInstance == null)
        {
            synchronized (ISUPAMSByJNA.class)
            {
                String strDllPath = "";
                try
                {
                    //System.setProperty("jna.debug_load", "true");
                    if(CommonMethod.isWindows())
                        strDllPath = CommonMethod.GetLibPathByArch() + "HCISUPAlarm";
                    else if(CommonMethod.isLinux())
                        strDllPath = CommonMethod.GetLibPathByArch() + "libHCISUPAlarm.so";
                    m_AMSInstance = (ISUPAMSByJNA) Native.loadLibrary(strDllPath, ISUPAMSByJNA.class);
                }catch (Exception ex) {
                    System.out.println("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
                    return false;
                }
            }
        }
        return true;
    }

    public static ISUPAMSByJNA GetAlarmInstance()
    {
        return m_AMSInstance;
    }

    public boolean IsRunning(){return m_bIsRunning;}
}
